// (C) Copyright 2012 Enlightv. All rights reserved.

`timescale 1ns/100ps
`default_nettype none

module vin_fmt_detect 
#(parameter
    MAX_IN_WIDTH = 0,
    MAX_IN_HEIGHT = 0,
    IN_WIDTH_BW = 0,
    IN_HEIGHT_BW = 0
)
(
    input  wire I_video_pclk,
    input  wire I_video_vsync,
    input  wire I_video_de,
    // 
    input  wire I_sclk,
    input  wire I_rst_n,
    output reg  O_video_start,
    output reg  O_video_over,
    output reg  [ IN_WIDTH_BW - 1: 0] O_video_width,
    output reg  [ IN_HEIGHT_BW - 1: 0] O_video_height,
    output wire [ 7: 0] O_video_frame_rate,
    //
    output wire O_video_not_active
);

/******************************************************************************
                                <localparams>
******************************************************************************/

/******************************************************************************
                              <internal signals>
******************************************************************************/
reg  vsync_dly;
reg  vsync_polarity;
reg  [ IN_HEIGHT_BW - 1: 0] line_cnt;
reg  [ IN_WIDTH_BW - 1: 0] de_cnt;
reg  de_dly;
reg  [ IN_HEIGHT_BW - 1: 0] height;
reg  [ IN_WIDTH_BW - 1: 0] width;
reg  [ IN_WIDTH_BW - 1: 0] final_width;
reg  video_over;
reg  [ 15: 0] video_over_dly;
reg  video_over_ext;
(* ASYNC_REG = "TRUE" *) reg  video_over_ext_sync1, video_over_ext_sync2;
reg  video_over_ext_sync_dly1;
reg  video_over_ext_sync_dly2;
reg  video_start;
reg  [ 15: 0] video_start_dly;
reg  video_start_ext;
(* ASYNC_REG = "TRUE" *) reg  video_start_ext_sync1, video_start_ext_sync2;
reg  video_start_ext_sync_dly1;
reg  video_start_ext_sync_dly2;
reg  start_flag_sent;
reg  video_over_flag_dly;
(* ASYNC_REG = "TRUE" *) reg  video_vsync_ref_sync0, video_vsync_ref_sync1;
reg  video_vsync_ref_dly;
wire video_vsync_ref_pulse;
reg  [ 3: 0] vsync_ref_cnt;
reg  [ 4: 0] width_score;
reg  video_not_active;
reg  [ 1: 0] not_active_cnt;
reg  [ 5: 0] one_second_cnt;
reg  [ 7: 0] frame_rate_cnt;
reg  [ 7: 0] video_vsync_dly;
reg  video_vsync;
reg  [ IN_WIDTH_BW - 1: 0] video_width;
reg  [ IN_HEIGHT_BW - 1: 0] video_height;

/******************************************************************************
                                <module body>
******************************************************************************/
always @(posedge I_video_pclk)
    video_vsync_dly <= {video_vsync_dly[6:0], I_video_vsync};

always @(posedge I_video_pclk)
    if (video_vsync_dly == 'd0)
        video_vsync <= 1'b0;
    else if (video_vsync_dly == 'hff)
        video_vsync <= 1'b1;

//--------------------------------------------------------------------
// video pclk domain
//--------------------------------------------------------------------
always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        vsync_dly <= 1'b0;
    else
        vsync_dly <= video_vsync;

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        vsync_polarity <= 1'b0;
    else if (!de_dly && I_video_de)
        vsync_polarity <= video_vsync;

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        video_over <= 1'b0;
    else
        video_over <= (!vsync_polarity && video_vsync && !vsync_dly)
                    || (vsync_polarity && !video_vsync && vsync_dly);

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        video_start <= 1'b0;
    else
        video_start <= (vsync_polarity && video_vsync && !vsync_dly)
                    || (!vsync_polarity && !video_vsync && vsync_dly);

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        line_cnt <= 60;
    else if (video_over_dly[1])
        line_cnt <= 'd0;
    else if (I_video_de && !de_dly)
        line_cnt <= line_cnt + 1'b1;

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        height <= 60;
    else if (video_over)
        begin
        if (line_cnt <= 60)
            height <= 60;
        else if (line_cnt >= MAX_IN_HEIGHT)
            height <= MAX_IN_HEIGHT;
        else
            height <= line_cnt;
        end
 
always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        de_cnt <= 'd0;
    else if (!I_video_de)
        de_cnt <= 'd0;
    else
        de_cnt <= de_cnt + 1'b1;

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        de_dly <= 1'b0;
    else
        de_dly <= I_video_de;

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        width <= 60;
    else if (!I_video_de && de_dly)
        begin
        if (width != de_cnt && width_score == 0)
            width <= de_cnt;
        end
    
always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        width_score <= 'd0;
    else if (!I_video_de && de_dly)
        begin
        if (width == de_cnt)
            begin
            if (width_score != 5'b1_1111)
                width_score <= width_score + 1'b1;
            end
        else
            begin
            if (width_score != 0)
                width_score <= width_score - 1'b1;
            end
        end
 
always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        final_width <= 50;
    else if (width_score <= 16
        || width <= 60)
        final_width <= 50;
    else if (width >= MAX_IN_WIDTH)
        final_width <= MAX_IN_WIDTH;
    else
        final_width <= width;
 
always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        video_over_dly <= 'd0;
    else
        video_over_dly <= {video_over_dly[14:0],video_over};

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        video_over_ext <= 1'b0;
    else
        video_over_ext <= video_over_dly != 'd0;

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        video_start_dly <= 'd0;
    else
        video_start_dly <= {video_start_dly[14:0],video_start};

always @(posedge I_video_pclk or negedge I_rst_n)
    if (!I_rst_n)
        video_start_ext <= 1'b0;
    else
        video_start_ext <= video_start_dly != 'd0;

//--------------------------------------------------------------------
// sclk domain
//--------------------------------------------------------------------
always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        begin
        video_over_ext_sync1 <= 1'b0;
        video_over_ext_sync2 <= 1'b0;
        video_over_ext_sync_dly1 <= 1'b0;
        video_over_ext_sync_dly2 <= 1'b0;
        video_start_ext_sync1 <= 1'b0;
        video_start_ext_sync2 <= 1'b0;
        video_start_ext_sync_dly1 <= 1'b0;
        video_start_ext_sync_dly2 <= 1'b0;
        end
    else
        begin
        video_over_ext_sync1 <= video_over_ext;
        video_over_ext_sync2 <= video_over_ext_sync1;
        video_over_ext_sync_dly1 <= video_over_ext_sync2;
        video_over_ext_sync_dly2 <= video_over_ext_sync_dly1;
        video_start_ext_sync1 <= video_start_ext;
        video_start_ext_sync2 <= video_start_ext_sync1;
        video_start_ext_sync_dly1 <= video_start_ext_sync2;
        video_start_ext_sync_dly2 <= video_start_ext_sync_dly1;
        end

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_video_start <= 1'b0;
    else if (O_video_start)
        O_video_start <= 1'b0;
    else if (!start_flag_sent && !video_start_ext_sync_dly1 && video_start_ext_sync_dly2)
        O_video_start <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        start_flag_sent <= 1'b0;
    else if (O_video_over)
        start_flag_sent <= 1'b0;
    else if (O_video_start)
        start_flag_sent <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_video_over <= 1'b0;
    else if (O_video_over)
        O_video_over <= 1'b0;
    else if (start_flag_sent && !video_over_ext_sync_dly1 && video_over_ext_sync_dly2)
        O_video_over <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        video_over_flag_dly <= 1'b0;
    else
        video_over_flag_dly <= O_video_over;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        begin
        video_width <= 60;
        video_height <= 60;
        end
    else if (video_over_flag_dly)
        begin
        video_width <= final_width;
        video_height <= height;
        end

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        begin
        O_video_width <= 60;
        O_video_height <= 60;
        end
    else if (O_video_not_active)
        begin
        O_video_width <= 60;
        O_video_height <= 60;
        end
    else
        begin
        O_video_width <= video_width;
        O_video_height <= video_height;
        end

//--------------------------------------------------------------------
// video active detect
//--------------------------------------------------------------------
reg  [ 9: 0] cnt0;
reg  [ 10: 0] cnt1;
reg  sig_60Hz;

//always @(posedge I_sclk)
//    begin
//    cnt0 <= cnt0 + 1'b1;
//    if (cnt0 == 10'h3ff) cnt1 <= cnt1 + 1'b1;
//    sig_60Hz <= cnt1[10];
//    end

//always @(posedge I_sclk or negedge I_rst_n)
//    if (!I_rst_n)
//        begin
//        video_vsync_ref_sync0 <= 1'b0;
//        video_vsync_ref_sync1 <= 1'b0;
//        video_vsync_ref_dly <= 1'b0;
//        end
//    else
//        begin
//        video_vsync_ref_sync0 <= sig_60Hz;
//        video_vsync_ref_sync1 <= video_vsync_ref_sync0;
//        video_vsync_ref_dly <= video_vsync_ref_sync1;
//        end

//assign video_vsync_ref_pulse = !video_vsync_ref_dly && video_vsync_ref_sync1;

//always @(posedge I_sclk or negedge I_rst_n)
//    if (!I_rst_n)
//        vsync_ref_cnt <= 'd0;
//    else if (O_video_start)
//        vsync_ref_cnt <= 'd0;
//    else if (video_vsync_ref_pulse)
//        begin
//        if (vsync_ref_cnt != 10)
//            vsync_ref_cnt <= vsync_ref_cnt + 1'b1;
//        end

//always @(posedge I_sclk or negedge I_rst_n)
//    if (!I_rst_n)
//        video_not_active <= 1'b1;
//    else
//        video_not_active <= vsync_ref_cnt == 'd10 || video_width == 60 || video_height == 60;

assign O_video_not_active = 1'b0;
//always @(posedge I_sclk or negedge I_rst_n)
//    if (!I_rst_n)
//        O_video_not_active <= 1'b1;
//    else if (video_not_active)
//        O_video_not_active <= 1'b1;
//    else if (!video_not_active && not_active_cnt == 'd0)
//        O_video_not_active <= 1'b0;

//always @(posedge I_sclk or negedge I_rst_n)
//    if (!I_rst_n)
//        not_active_cnt <= 'd0;
//    else if (video_not_active)
//        not_active_cnt <= 'd3;
//    else if (!video_not_active && video_vsync_ref_pulse)
//        begin
//        if (not_active_cnt != 'd0)
//            not_active_cnt <= not_active_cnt - 1'b1;
//        end
//
//always @(posedge I_sclk)
//    if (one_second_cnt >= 'd60)
//        one_second_cnt <= 'd0;
//    else if (video_vsync_ref_pulse)
//        one_second_cnt <= one_second_cnt + 1'b1;
//
//always @(posedge I_sclk)
//    if (one_second_cnt == 60)
//        frame_rate_cnt <= 'd0;
//    else if (O_video_start)
//        begin
//        if (frame_rate_cnt != 8'hff)
//            frame_rate_cnt <= frame_rate_cnt + 1'b1;
//        end

assign O_video_frame_rate = 60;
//always @(posedge I_sclk)
//    if (one_second_cnt == 60)
//        O_video_frame_rate <= frame_rate_cnt;
endmodule
`default_nettype wire

